<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    // 手写new
    function _new(fn, ...rest) {
        //基于fn的prototype构建对象的原型
        const obj = Object.create(fn.prototype);
        //将obj作为fn的this，继承其属性，并获取返回结果为result
        const result = fn.apply(obj, rest);
        //根据result对象的类型决定返回结果（null 和 undefined不处理）
        return result instanceof Object ? result : obj;
    }
    function _new(fun, ...rest) {
        const obj = {};
        obj.__proto__ = fun.prototype;
        const result = fun.apply(obj, rest);
        return result instanceof Object ? result : obj;
    }

    //手写instanceof
    function _instanceof(left, right) {
        left = left.__proto__;
        right = right.prototype;
        while (true) {
            if (left === null) {
                return false;
            } else if (left === right) {
                return true;
            }
            left = left.__proto__;
        }
    }

    //手写节流
    function 节流(fun, time) {
        let previous = 0;
        return function (...args) {
            let now = Date.now();
            if (now - previous > time) {
                fun.apply(this, args);
                previous = now;
            }
        }
    }

    //手写防抖
    function 防抖(fun, time) {
        let timer = null;
        return function (...args) {
            if (timer) clearTimeout(timer);
            let _this = this;
            timer = setTimeout(() => {
                fun.apply(_this, args)
            }, time);
        }
    }

    //reduce实现map (thisArr为回调函数的this指向)
    Array.prototype._map = function (fun, thisArr) {
        let arr = [];
        thisArr = thisArr || [];
        this.reduce((prev, curr, index) => {
            arr.push(fun.call(thisArr, curr, index))
        }, [])
        return arr;
    }
    var res = [1, 2, 3]._map(function (item, index) {
        console.log(this);
        return item * index
    }, [2, 3, 4, 5]);
    console.log(res);

    //手写bind
    Function.prototype._bind = function (thisArg, ...res) {
        if (typeof this !== 'function') return;
        var _this = this;
        return function () {
            return _this.apply(thisArg, res.concat(arguments));
        }
    }

    // 手写call
    Function.prototype._call = function (thisArg, ...res) {
        let obj = thisArg || window;
        obj.fn = this; //获取到调用的function
        return obj.fn(...res);
    }

    // 手写Promise.all
    Promise.prototype._all = function (iterators) {
        const arr = Array.from(iterators);
        const len = promises.length;
        let count = 0;
        let result = [];
        return new Promise((resolve, reject) => {
            arr.forEach((p, i) => {
                Promise.resolve(p).then((res) => {
                    count++;
                    result[i] = res;
                    if (count === len) {
                        resolve(result);
                    }
                })
            })
        }).catch(err => {
            reject(err);
        })
    }

    // 用setTimeout实现setInterval
    function _setInterval(fun, interval) {
        var timer = setTimeout(() => {
            fun();
            _setInterval(fun, interval);
            clearTimeout(timer);
        }, interval);
    }
    _setInterval(() => {
        console.log(1);
    }, 2000)

    // 手写函数柯里化
    function curry(fun, ...args) {
        let len = fun.length; //函数的参数个数，相当于arguments的长度
        return function () {
            allArgs = [...args, ...arguments];
            if (allArgs.length >= len) {
                return fun.apply(null, allArgs);
            } else {
                return curry(fun, ...allArgs);
            }
        }
    }
    function sum(a, b, c, d, e) {
        var count = 0;
        for (let i = 0; i < arguments.length; i++) {
            count += arguments[i]
        }
        return count;
    }
    var sumCurry = curry(sum, 1, 9);
    var res = sumCurry(2)(3)(1);
    console.log(res);

    // 柯里化实现无限参数和
    function add() {
        var allArgs = [...arguments];
        var adder = function () {
            allArgs.push(...arguments);
            return adder;
        }
        adder.valueOf = function () {
            return allArgs.reduce((total, curr) => (total + curr));
        }
        return adder;
    }
    var result = add(1, 2, 3)(4)(5, 6)(7, 8, 9)
    console.log(result);
    console.log(result.valueOf());

    // JSON.parse原理
    var json = '{"a":"1","b":2}'
    var obj = eval("(" + json + ")"); // 必须加括号，形成一个表达式整体
    console.log(obj);

    var obj = new Function("return" + json)
    console.log(obj());

    // Object 与 Map
    var map = new Map([['a', 1], ['b', 2]]);
    map.set({}, 22222)
    var temp = map.get('a')
    map.delete('a')
    map.set('a', temp)
    console.log(map)
    var obj = {
        1: 0,
        a: 111,
        b: 222,
        z: 333,
        c: 555,
        [Symbol()]: 77777
    }
    delete obj['a']
    obj['a'] = 999;
    console.log(Object.keys(obj));
    for (let item in obj) {
        console.log(item);
    }

    var set = new Set([1, 2, 3, 4, 5]);
    for (let k of set.values()) {
        console.log(k);
    }

    function lazyQueue() {
        this.funArr = [];
        this.timeArr = [];
        this.currTime = 0;
        this.timerArr = [];
        this.sleep = function (time, fun) {
            this.currTime += time;
            this.timeArr.push(this.currTime);
            this.funArr.push(fun);
            return this;
        }
        this.start = function () {
            this.funArr.map((fun, i) => {
                var temp = setTimeout(fun, this.timeArr[i]);
                this.timerArr.push(temp)
            })
        }
        this.stop = function () {
            this.timerArr.forEach(item => {
                clearTimeout(item)
            })
        }
    }
    var a = new lazyQueue()
    a.sleep(1000, () => {
        console.log(1);
    }).sleep(2000, () => {
        console.log(2);
    }).sleep(3000, () => {
        console.log(3)
    }).start()
    setTimeout(() => {
        a.stop()
    }, 3);

    // 将数组转化为树形结构
    var arr = [
        { id: 1, name: 'a', parentId: 0 },
        { id: 2, name: 'b', parentId: 0 },
        { id: 3, name: 'c', parentId: 1 },
        { id: 4, name: 'd', parentId: 1 },
        { id: 5, name: 'd', parentId: 2 },
        { id: 6, name: 'e', parentId: 3 },
        { id: 7, name: 'f', parentId: 4 },
    ]
    const transform = function (arr) {
        var map = {};
        arr.forEach((item, i) => {
            map[item.id] = item;
        })
        var res = [];
        for (let item of arr) {
            if (item.parentId in map) {
                const parent = map[item.parentId];
                parent.children = parent.children || [];
                parent.children.push(item)
            } else {
                res.push(item);
            }
        }
        return res;
    }
    var result = transform(arr);
    console.log(JSON.stringify(result));

</script>

</html>